/*
 * Copyright 2014 by État de Genève (Switzerland)
 * All rights reserved.
 *
 * Author: ELCA Informatique SA
 */
define(['plugins/router',
        'services/api', 
        'services/config', 
        'services/notifier', 
        'services/user',
        'q',
        'i18n'],
    function (router, api, config, notifier, user, Q, i18n) {

    return {
    	login: login,
    	logout: logout,
    	loadConfigData: loadConfigData,
    	loadMenu: loadMenu,
        getUsers: getUsers
    };
    
    function login(data) {
        return api.post('login', data)
            .then(handleResponce)
            .then(function (resultWithResponce) {
            	if (resultWithResponce.result.user) {
    	    		user.initial(resultWithResponce.result.user);
        		}
            })
            .then(function () {
        		if (user.isAuthenticated()) {
        			location.href = "#";
        		}
        	});
    }
    
    function logout() {
        return api.get('logout')
            .then(handleResponce)
            .then(function () {
            	user.clear();
        	})
        	.then(function () {
            	location.href = "#";
        	});
        
    }
    
    function loadMenu(menuId) {
        return api.get('menu/' + (menuId || ''))
            .then(handleResponce)
            .then(function(data) {
                return data.result;
            });
    }

    /**
     * Initial load of data and user.
     */
    function loadConfigData() {
        return api.get('initial')
            .then(handleResponce)
            .then(function (data) {
                return data.result;
            });
    }
    
    function getUsers() {
        return api.get('user')
            .then(handleResponce)
            .then(function (data) {
                return data.result;
            });
    }

    /**
     * Builds a query object with all information needed to retrieve a list from the API
     * @param quickSearchText
     * a string from the quicksearch box
     * @param searchInboxOnly
     * a bool telling wether or not to search in the inbox only (not applicable for 'seach first' lists)
     * @param sortObj
     * an object with an id (column name) and a sort direction (ASC or DESC)
     * @param pageObj
     * an object with paging information: pageNbr = current page, and pageSize = total record to fetch
     * @param filterObj
     * an object (key value) containing each advanced search field (with some values probably equal to null)
     */
    function buildQueryObject(quickSearchText, searchInboxOnly, sortObj, pageObj, filterObj) {

        quickSearchText = quickSearchText || '';

        // filter out sort and page object's useless properties for query
        // ..in case page and sort are passed from more complex object, like a Pager
        var sort = sortObj ?
        {
            dir: sortObj.dir,
            id: sortObj.id
        } : {
            dir: 'ASC',
            id: ''
        };

        var page = pageObj ?
        {
            pageNbr: pageObj.pageNbr,
            pageSize: pageObj.pageSize
        } : {
            pageNbr: 1,
            pageSize: config.api.defaultListPageSize
        };

        // transform advanced search key-value object in an array of values (takes only values not nullish)
        var filtersArr = _.compact(_.map(_.pairs(filterObj), function (fieldValue) {
            if (fieldValue[1]) {
                return {
                    field: fieldValue[0],
                    // if value is an object with a key, it comes from a select element and so we take only the key
                    // otherwise we take the value itself
                    value: fieldValue[1].key || fieldValue[1]
                };
            }
            return null;
        }));

        return {
            quickSearch: quickSearchText.toString(),
            inboxOnly: searchInboxOnly || false,
            sort: sort,
            page: page,
            filters: filtersArr
        };
    }

    /**
     * retrieve an entity list from the type.
     * The query should be built by the buildQueryObject func above
     */
    function getListForType(type, query) {

        return api.post('list/' + type, query)
            .catch(function() {
                //TODO [dge, 2] temporary removes 500 popup when a service does not exists
                return {
                    result: [],
                    alerts: []
                };
            })
            .then(handleResponce)
            .then(function (resultWithAlerts) {
                return {
                    results: resultWithAlerts.result.rows,
                    count: resultWithAlerts.result.totalCount
                };
            });
    }

    /**
     * retrieve an empty object for the given type in a remote json file.
     * @param type
     * Entity type (PersonnePhysique, PoursuiteOrdinaire, ...)
     */
    function createEmpty(type) {
        return api.getJsonFile('model.' + type + '.json')
            .then(function(result) {
                return {
                    data: result,
                    lock: user.initials
                };
            });
    }

    /**
     * get an entity data for a detail form.
     */
    function getDataByIdAndType(id, type) {

        if(id === 'new') {
            return createEmpty(type);
        }

        return api.get(type + '/' + id)
            .then(handleResponce)
            .then(function (resultWithAlerts) {
                return {
                    data: resultWithAlerts.result,
                    lock: resultWithAlerts.result.lockOwner
                };
            });
    }

    /**
     * Try to lock an entity data for edit in a detail form
     */
    function tryLockData(id, type) {

        return api.get(type + '/' + id + '/lock')
            .then(handleResponce)
            .then(function (resultWithAlerts) {
                return {
                    data: resultWithAlerts.result,
                    lock: resultWithAlerts.result.lockOwner
                };
            });
    }

    /**
     * the save function needs no id in the URL (it will be determined from the data posted)
     */
    function saveDataByType(type, entity) {

        return api.post(type + '/save', entity)
            .then(handleResponce)
            .then(function (resultWithAlerts) {
                // if entity is null, keep the current entity data
                if(!resultWithAlerts.result) {
                    resultWithAlerts.result = entity;
                }

                return {
                    data: resultWithAlerts.result,
                    lock: resultWithAlerts.result.lockOwner,
                    validationMessages: resultWithAlerts.validation
                };
            });
    }

    /**
     * Called after each API success response.
     * Handles the 'alerts[]' array present in each response (should show them at the top of the UI)
     */
    function handleResponce(resultWithResponce) {

        if (resultWithResponce && resultWithResponce.response) {

            // clear notifications on each server call
            notifier.clearNotifications();

            _.each(resultWithResponce.response, function(response) {
                notifier.notify(response.message, undefined, response.type);
            });
        }

        return resultWithResponce;
    }
});